import {Object3D, WebGLRenderer } from "three";
import Polygon from "./Polygon";
import { Point } from "../../renderExtension/types/Point";
import Const from "../../application/constants/Const";

/**
 * 构建带孔洞的多边形
 */
export default class HolePolygon extends Object3D {

    /**
     * 构建带孔洞的多边形
     * @param pathArray 设置多个多边形的数据，pathArray的第一个元素必须是外部多边形，后边的元素是内部的孔洞多边形
     * pointArray 多边形数组
     * textureImg 多边形贴图用到的纹理
     * transparent 多边形是否开启透明度
     * alphaValue 透明值，当transparent为false时，这个值无效
     * color 非孔洞部分的颜色
     */
    constructor(pathArray: Array<{ pointArray: Array<Point>, textureImg: string, transparent: boolean, alphaValue: number, color: string }>){
        super();
        this.setPath(pathArray);
    }

    //设置多个多边形的数据，pathArray的第一个元素必须是外部多边形
    private setPath(pathArray: Array<{ pointArray: Array<Point>, textureImg: string, transparent: boolean, alphaValue: number, color: string }>) {
        for (let i = 0; i < pathArray.length; i++) {
            let polygonData = pathArray[i];
            if (i == 0) {//构建外部多边形
                this.buildOuterPolygon(polygonData); //renderOrder: 11
            } else {//构建内部多边形
                this.firstRendeInnerPolgon(polygonData); //renderOrder: 10
                this.secondRendInterPolygon(polygonData); //renderOrder: 12
            }
        }
    }

    //第一遍渲染内部多边形，此次渲染只是为了在模板缓冲区中写入值，不覆盖颜色缓冲区
    private firstRendeInnerPolgon(data: { pointArray: Array<Point>, textureImg: string, transparent: boolean, alphaValue: number, color: string }) {
        let polygonData = {
            pointArray: data.pointArray,  //多边形的顶点数组
            textureImg: data.textureImg, //贴在多边形上的图片
            alphaValue: data.alphaValue,  //透明值
            color: data.color, //多边形的颜色
            colorWrite: false
        };
        var innerPolygon = new Polygon(polygonData);
        innerPolygon.renderOrder = 10;
        innerPolygon.onBeforeRender = function(renderer: WebGLRenderer){
            let gl = renderer.getContext();
            gl.enable(gl.STENCIL_TEST);
            gl.stencilFunc(gl.ALWAYS, Const.StencilRefValue.HolePOlygonRef, 0xff);
            gl.stencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE);
        };
        innerPolygon.onAfterRender = function(renderer: WebGLRenderer){
            let gl = renderer.getContext();
            gl.disable(gl.STENCIL_TEST);
        };

        this.add(innerPolygon);
    }

    //第二遍渲染内部多边形，此次渲染根据外部多边形的模板值做测试，判断是否更新颜色缓冲区
    private secondRendInterPolygon(data: { pointArray: Array<Point>, textureImg: string, transparent: boolean, alphaValue: number, color: string }) {
        let polygonData = {
            pointArray: data.pointArray,  //多边形的顶点数组
            textureImg: data.textureImg, //贴在多边形上的图片
            alphaValue: data.alphaValue || 0,  //透明值
            color: data.color, //多边形的颜色
            transparent: data.transparent || true,
            // colorWrite: true
        };
        var innerPolygon = new Polygon(polygonData);
        innerPolygon.renderOrder = 12;

        innerPolygon.onBeforeRender = function(renderer: WebGLRenderer){
            let gl = renderer.getContext();
            gl.enable(gl.STENCIL_TEST);
            gl.stencilFunc(gl.NOTEQUAL, Const.StencilRefValue.HolePOlygonRef, 0xff);
            gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
        };
        innerPolygon.onAfterRender = function(renderer: WebGLRenderer){
            let gl = renderer.getContext();
            gl.disable(gl.STENCIL_TEST);
        };

        this.add(innerPolygon);
    }

    //渲染外部多边形；这次渲染做两件事：1.根据内部多边形的第一次渲染的模板缓冲区的值，判断是否更新颜色缓冲区；2.覆盖这个多边形区域内的全部模板缓冲区
    private buildOuterPolygon(data: { pointArray: Array<Point>, textureImg: string, transparent: boolean, alphaValue: number, color: string }) {
        let polygonData = {
            pointArray: data.pointArray,  //多边形的顶点数组
            textureImg: data.textureImg, //贴在多边形上的图片
            alphaValue: data.alphaValue,  //透明值
            color: data.color, //多边形的颜色
            transparent: data.transparent,
            // colorWrite: true
        };
        var innerPolygon = new Polygon(polygonData);
        innerPolygon.renderOrder = 11;

        innerPolygon.onBeforeRender = function(renderer: WebGLRenderer){
            let gl = renderer.getContext();
            gl.enable(gl.STENCIL_TEST);
            gl.stencilFunc(gl.NOTEQUAL, Const.StencilRefValue.HolePOlygonRef, 0xff);
            gl.stencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE);
        };
        innerPolygon.onAfterRender = function(renderer: WebGLRenderer){
            let gl = renderer.getContext();
            gl.disable(gl.STENCIL_TEST);
        };

        this.add(innerPolygon);
    }

}